package com.zmn.plat.business.impl.orderconfig.orderstock;

import java.util.*;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dto.VtDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.holiday.HoliDayUtils;
import com.zmn.plat.business.interfaces.company.BaseCompanyAreaBService;
import com.zmn.plat.business.interfaces.orderconfig.orderstock.OrderStockBService;
import com.zmn.plat.business.interfaces.product.ProductBService;
import com.zmn.plat.common.dictionary.PlatErrorCodeDict;
import com.zmn.plat.common.dto.orderconfig.orderstock.OrderStockDRO;
import com.zmn.plat.common.dto.orderconfig.orderstock.SpOrderStockDRO;
import com.zmn.plat.common.dto.orderconfig.orderstock.SpOrderStockWarningDRO;
import com.zmn.plat.common.dto.product.ProductAllMsgInfoDRO;
import com.zmn.plat.common.dto.product.ProductDIO;
import com.zmn.plat.common.exception.PlatException;
import com.zmn.plat.model.entity.orderconfig.orderstock.plat.PlatConfig;
import com.zmn.plat.model.entity.orderconfig.orderstock.plat.PlatConfigQuery;
import com.zmn.plat.model.entity.orderconfig.orderstock.sp.SpConfig;
import com.zmn.plat.model.entity.orderconfig.orderstock.sp.SpWarningConfig;
import com.zmn.plat.model.entity.orderconfig.orderstock.sp.SpWarningConfigQuery;
import com.zmn.plat.services.interfaces.orderconfig.oderstock.plat.PlatConfigService;
import com.zmn.plat.services.interfaces.orderconfig.oderstock.sp.SpConfigService;
import com.zmn.plat.services.interfaces.orderconfig.oderstock.sp.SpWarningConfigService;

import lombok.extern.log4j.Log4j2;

/**
 * 描述：订单库存综合BService实现类
 *
 * @author: tanghongjun
 * @time: 2020/4/21 10:18
 */
@Service
@Log4j2
public class OrderStockBServiceImpl implements OrderStockBService {

    /**
     * 服务公司Dubbo接口
     */
    @Resource
    BaseCompanyAreaBService baseCompanyAreaBService;

    /**
     * 产品Dubbo接口
     */
    @Resource
    ProductBService productBService;

    @Resource
    SpConfigService spConfigService;

    @Resource
    PlatConfigService platConfigService;

    @Resource
    OrderStockBService orderStockBService;

    @Resource
    SpWarningConfigService spWarningConfigService;

    @Override
    @Cacheable(cacheNames = "redis5m", key = "'scm:orderstock:plat:stock:plat:'+#p0+':city:'+#p1+':date:'+#p2+':product:'+#p3", unless = "#result == null")
    public OrderStockDRO getOrderStockStatusByCityAndDateAndShowProductId(Integer plat, Integer cityId, Date date, Integer showProductId) {
        if (Objects.isNull(cityId) || Objects.isNull(date) || Objects.isNull(showProductId)) {
            log.error("getOrderStockStatusByCityAndDateAndShowProductId参数不合法：{}，{}，{}，{}", plat, cityId, date, showProductId);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }
        ProductDIO productDIO = new ProductDIO();
        productDIO.setProductId(showProductId);
        productDIO.setStatus(GlobalConsts.YES);
        List<ProductAllMsgInfoDRO> listResponseDTO = productBService.listByDIO(productDIO); // 巨坑啊！！！为啥去查这个接口？？？ 待优化
        ProductAllMsgInfoDRO product = listResponseDTO.get(0);

        return orderStockBService.getCityOrderStockByPlatAndCityAndCategAndDate(plat, cityId, product.getProductBaseDRO().getServCategId(), date);
    }

    @Override
    @Cacheable(cacheNames = "redis5m", key = "'scm:orderstock:plat:stock:plat:'+#p0+':city:'+#p1+':serv:'+#p2+':categ:'+#p3+':date:'+#p4", unless = "#result == null")
    public OrderStockDRO getCityOrderStockByPlatAndCityAndCategAndDate(Integer plat, Integer cityId, Integer servCategId, Date date) {
        if (Objects.isNull(plat) || Objects.isNull(cityId) || Objects.isNull(servCategId) || Objects.isNull(date)) {
            log.error("getCityOrderStockByPlatAndCityAndCategAndDate 参数为 plat:{},cityId:{},servCategId:{},date:{},errorCode:{}", plat, cityId, servCategId, date,
                PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        // 判断是否为节假日
        boolean falg = HoliDayUtils.isHoliDay(date);

        // 计算城市库存
        List<VtDTO> spList = baseCompanyAreaBService.listCompanyByAreaId(cityId, plat);
        List<Integer> spIdList = spList.stream().map(VtDTO::getValue).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(spIdList)) {
            log.error("spIdList is empty.errorCode:{}", PlatErrorCodeDict.ERROR_CODE_ORDERCONFIG_SERVICER_NOT_EXIST_CITY);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_ORDERCONFIG_SERVICER_NOT_EXIST_CITY);
        }

        // 查询当天关闭库存的服务商
        List<SpConfig> spCloseList = spConfigService.listCloseSpBySpIdListAndCityAndCateg(spIdList, date, cityId, servCategId);
        List<Integer> spCloseIdList = spCloseList.stream().map(SpConfig::getSpId).collect(Collectors.toList());

        // 查询服务商库存
        List<SpConfig> spOpenList = spConfigService.listNotCloseSpBySpIdListAndCityAndCateg(spIdList, date, cityId, servCategId);
        Map<Integer, SpConfig> spOpenMap = spOpenList.stream().collect(Collectors.toMap(SpConfig::getSpId, e -> e));

        // 查询平台库存
        PlatConfigQuery query = new PlatConfigQuery();
        query.setPlat(plat);
        query.setServCategId(servCategId);
        query.setStatus(GlobalConsts.YES);
        List<PlatConfig> platConfigList = platConfigService.listByQuery(query);
        PlatConfig platConfig = null;
        if (CollectionUtil.isNotNullOrEmpty(platConfigList)) {
            platConfig = platConfigList.get(0);
        }

        // 计算库存
        OrderStockDRO orderStockDRO = new OrderStockDRO();
        int orderStockNum = 0;
        int spId;
        SpConfig spConfig;
        for (int i = 0; i < spIdList.size(); i++) {
            spId = spIdList.get(i);
            if (spCloseIdList.contains(spId)) {
                continue;
            }
            spConfig = spOpenMap.get(spId);

            // 服务商配置不为空，走服务商配置
            if (Objects.nonNull(spConfig)) {
                if (spConfig.getStock() == -1) {
                    orderStockDRO.setUnlimited(1);
                    orderStockDRO.setColseOrNot(false);
                    return orderStockDRO;
                }
                orderStockNum += falg ? Math.round(spConfig.getStock() * spConfig.getCoefficient()) : spConfig.getStock();
            } else {
                // 服务商配置为空，走平台配置
                // 平台配置也为空，则表示不限制
                if (Objects.isNull(platConfig) || platConfig.getStock() == -1) {
                    orderStockDRO.setUnlimited(1);
                    orderStockDRO.setColseOrNot(false);
                    return orderStockDRO;
                }
                orderStockNum += falg ? Math.round(platConfig.getStock() * platConfig.getCoefficient()) : platConfig.getStock();
            }
        }
        orderStockDRO.setOrderStockNum(orderStockNum);
        orderStockDRO.setColseOrNot(orderStockNum == 0);
        orderStockDRO.setUnlimited(2);
        return orderStockDRO;
    }

    @Override
    @Cacheable(cacheNames = "redis5m", key = "'scm:orderstock:sp:stock:plat:'+#p0+':city:'+#p1+':spid:'+#p2+':serv:'+#p3+':categ:'+#p4+':date:'+#p5", unless = "#result == null")
    public OrderStockDRO getSpOrderStockByPlatAndCityAndSpAndCategAndDate(Integer plat, Integer cityId, Integer spId, Integer servCategId, Date date) {
        if (Objects.isNull(plat) || Objects.isNull(cityId) || Objects.isNull(spId) || Objects.isNull(servCategId) || Objects.isNull(date)) {
            log.error("参数不合法 plat:{}，cityId:{}，date:{}，servCategId:{}，spId{}", plat, cityId, date, servCategId, spId);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        OrderStockDRO orderStockDRO = new OrderStockDRO();

        // 查询当天关闭库存的服务商
        List<SpConfig> spCloseList = spConfigService.listCloseSpBySpIdListAndCityAndCateg(Arrays.asList(spId), date, cityId, servCategId);

        // 判断是否为节假日
        boolean falg = HoliDayUtils.isHoliDay(date);

        // 查询服务商库存
        List<SpConfig> spOpenList = spConfigService.listBySpIdListAndCityAndCateg(Arrays.asList(spId), date, cityId, servCategId);
        if (CollectionUtil.isNotNullOrEmpty(spOpenList)) {
            SpConfig spConfig = spOpenList.get(0);
            if (spConfig.getStock() == -1) {
                orderStockDRO.setColseOrNot(CollectionUtil.isNotNullOrEmpty(spCloseList));
                orderStockDRO.setUnlimited(1);
                return orderStockDRO;
            }
            int orderStockNum = falg ? (int)Math.round(spConfig.getStock() * spConfig.getCoefficient()) : spConfig.getStock();
            orderStockDRO.setOrderStockNum(orderStockNum);
            orderStockDRO.setUnlimited(2);
            orderStockDRO.setColseOrNot(CollectionUtil.isNotNullOrEmpty(spCloseList));
            return orderStockDRO;
        }

        // 查询平台库存
        PlatConfigQuery query = new PlatConfigQuery();
        query.setPlat(plat);
        query.setServCategId(servCategId);
        // query.setCategTwoId(categId);
        query.setStatus(GlobalConsts.YES);
        List<PlatConfig> platConfigList = platConfigService.listByQuery(query);
        PlatConfig platConfig = null;
        if (CollectionUtil.isNotNullOrEmpty(platConfigList)) {
            platConfig = platConfigList.get(0);
            if (platConfig.getStock() == -1) {
                orderStockDRO.setColseOrNot(CollectionUtil.isNotNullOrEmpty(spCloseList));
                orderStockDRO.setUnlimited(1);
                return orderStockDRO;
            }

            int orderStockNum = falg ? (int)Math.round(platConfig.getStock() * platConfig.getCoefficient()) : platConfig.getStock();
            orderStockDRO.setOrderStockNum(orderStockNum);
            orderStockDRO.setColseOrNot(CollectionUtil.isNotNullOrEmpty(spCloseList));
            orderStockDRO.setUnlimited(2);
            return orderStockDRO;
        }

        // 都没有配置，默认不受库存限制
        orderStockDRO.setColseOrNot(CollectionUtil.isNotNullOrEmpty(spCloseList));
        orderStockDRO.setUnlimited(1);
        return orderStockDRO;
    }

    @Override
    @Cacheable(cacheNames = "redis5m", key = "'scm:orderstock:sp:order:plat:'+#p0+':city:'+#p1+':spids:'+#p2+':servCategId:'+#p3+':categId:'+#p4+':date:'+#p5",
        unless = "#reslut == null || #result.size() <= 0")
    public List<SpOrderStockDRO> getSpOrderStockByPlatAndCityAndSpListAndCategAndDate(Integer plat, Integer cityId, List<Integer> spIdList, Integer servCategId, Date date) {
        if (Objects.isNull(plat) || Objects.isNull(cityId) || org.apache.shiro.util.CollectionUtils.isEmpty(spIdList) || Objects.isNull(servCategId) || Objects.isNull(date)) {
            log.error("参数不合法：plat:{}，cityId:{}，date:{}，servCategId:{}，spIdList:{}", plat, cityId, date, servCategId, spIdList);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        // 判断是否为节假日
        boolean falg = HoliDayUtils.isHoliDay(date);

        // 查询当天关闭库存的服务商
        List<SpConfig> spCloseList = spConfigService.listCloseSpBySpIdListAndCityAndCateg(spIdList, date, cityId, servCategId);
        List<Integer> spCloseIdList = spCloseList.stream().map(SpConfig::getSpId).collect(Collectors.toList());

        // 查询服务商库存
        List<SpConfig> spOpenList = spConfigService.listBySpIdListAndCityAndCateg(spIdList, date, cityId, servCategId);
        Map<Integer, SpConfig> spOpenMap = spOpenList.stream().collect(Collectors.toMap(SpConfig::getSpId, e -> e));

        // 查询平台库存
        PlatConfigQuery query = new PlatConfigQuery();
        query.setPlat(plat);
        query.setServCategId(servCategId);
        // query.setCategTwoId(categId);
        query.setStatus(GlobalConsts.YES);
        List<PlatConfig> platConfigList = platConfigService.listByQuery(query);
        PlatConfig platConfig = null;
        if (CollectionUtil.isNotNullOrEmpty(platConfigList)) {
            platConfig = platConfigList.get(0);
        }

        // 计算库存
        List<SpOrderStockDRO> spOrderStockDROList = new ArrayList<>(spIdList.size());
        SpOrderStockDRO orderStockDRO;
        int spId;
        SpConfig spConfig;
        int orderStockNum;
        for (int i = 0; i < spIdList.size(); i++) {
            spId = spIdList.get(i);
            orderStockDRO = new SpOrderStockDRO();
            spConfig = spOpenMap.get(spId);

            // 服务商配置不为空，走服务商配置
            if (Objects.nonNull(spConfig)) {
                if (spConfig.getStock() == -1) {
                    orderStockDRO.setUnlimited(1);
                    orderStockDRO.setColseOrNot(spCloseIdList.contains(spId));
                    orderStockDRO.setSpId(spId);
                    spOrderStockDROList.add(orderStockDRO);
                } else {
                    orderStockNum = falg ? (int)Math.round(spConfig.getStock() * spConfig.getCoefficient()) : spConfig.getStock();
                    orderStockDRO.setOrderStockNum(orderStockNum);
                    orderStockDRO.setColseOrNot(spCloseIdList.contains(spId));
                    orderStockDRO.setUnlimited(2);
                    orderStockDRO.setSpId(spId);
                    spOrderStockDROList.add(orderStockDRO);
                }

            } else {
                // 服务商配置为空，走平台配置
                // 平台配置也为空，则表示不限制
                if (Objects.isNull(platConfig) || platConfig.getStock() == -1) {
                    orderStockDRO.setUnlimited(1);
                    orderStockDRO.setColseOrNot(spCloseIdList.contains(spId));
                    orderStockDRO.setSpId(spId);
                    spOrderStockDROList.add(orderStockDRO);
                } else {
                    orderStockNum = falg ? (int)Math.round(platConfig.getStock() * platConfig.getCoefficient()) : platConfig.getStock();
                    orderStockDRO.setOrderStockNum(orderStockNum);
                    orderStockDRO.setColseOrNot(spCloseIdList.contains(spId));
                    orderStockDRO.setUnlimited(2);
                    orderStockDRO.setSpId(spId);
                    spOrderStockDROList.add(orderStockDRO);
                }
            }
        }

        return spOrderStockDROList;
    }

    @Override
    public SpOrderStockWarningDRO getSpOrderStockWarning(Integer cityId, Integer spId, Integer servCategId, Integer categOneId, Integer categTwoId, Date date) {

        log.info("getSpOrderStockWarning params: cityId: {} spId: {} servCategId: {} categOneId: {} categTwoId:{} date:{}", cityId, spId, servCategId, categOneId, categTwoId, date);
        if (NumberUtil.isNullOrZero(cityId) || NumberUtil.isNullOrZero(spId) || NumberUtil.isNullOrZero(servCategId) || NumberUtil.isNullOrZero(categOneId)
            || NumberUtil.isNullOrZero(categTwoId) || Objects.isNull(date)) {
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PANAM_NULL);
        }

        SpWarningConfigQuery query = new SpWarningConfigQuery();
        query.setCityId(cityId);
        query.setSpId(spId);
        query.setServCategId(servCategId);
        query.setCategOneId(categOneId);
        query.setCategTwoId(categTwoId);
        List<SpWarningConfig> warningConfigList = spWarningConfigService.listByQuery(query);
        if (CollectionUtil.isNullOrEmpty(warningConfigList)) {
            // 该分类未配置预警量, 则不限制
            return new SpOrderStockWarningDRO();
        }
        SpWarningConfig spWarningConfig = warningConfigList.get(0);
        SpOrderStockWarningDRO dro = new SpOrderStockWarningDRO();

        // 判断是否为节假日
        boolean falg = HoliDayUtils.isHoliDay(date);
        int warningStock = falg ? (int)Math.round(spWarningConfig.getStock() * spWarningConfig.getCoefficient()) : spWarningConfig.getStock();

        dro.setWarningStock(warningStock);
        dro.setWarningProportion(spWarningConfig.getProportion());
        log.info("getSpOrderStockWarning return: {}", dro.toString());
        return dro;
    }
}
